{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# LLVM IR 基本概念\n",
    "\n",
    "参考：[LLVM IR 基本概念](https://chenzomi12.github.io/aisystem-docs/03Compiler01Tradition/05LLVMIR.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 编译器常见的作用是将源高级语言的代码编译到某种中间表示（Intermediate Representation，一般称为 IR），然后再将 IR 翻译为目标体系结构（具体硬件比如 MIPS 或 X86）的汇编语言或者硬件指令。\n",
    "> LLVM IR 提供了一种抽象层，使程序员可以更灵活地控制程序的编译和优化过程，同时保留了与硬件无关的特性。通过使用 LLVM IR，开发人员可以更好地理解程序的行为，提高代码的可移植性和性能优化的可能性。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## LLVM IR 示例与语法\n",
    "\n",
    "编写简单的 C 语言程序，并将其编译为 LLVM IR。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "temp_dir = \".temp\"\n",
    "!mkdir -p $temp_dir"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing .temp/test.c\n"
     ]
    }
   ],
   "source": [
    "%%file $temp_dir/test.c\n",
    "#include <stdio.h>\n",
    "\n",
    "void test(int a, int b)\n",
    "{\n",
    "    int c = a + b;\n",
    "}\n",
    "\n",
    "int main(void)\n",
    "{\n",
    "    int a = 10;\n",
    "    int b = 20;\n",
    "    test(a, b);\n",
    "    return 0;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用 Clang 编译器将 C 语言源文件 `test.c` 编译成 LLVM 格式的中间代码。具体参数的含义如下：\n",
    "- `clang`：Clang 编译器\n",
    "- `-S`：生成汇编代码而非目标文件\n",
    "- `-emit-llvm`：生成 LLVM IR 中间代码\n",
    "- `test.c`：要编译的 C 语言源文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "!clang -S -emit-llvm $temp_dir/test.c -o $temp_dir/test.ll"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 LLVM IR 中，所生成的 `.ll` 文件的基本语法为：\n",
    "\n",
    "- 指令以分号 `;` 开头表示注释\n",
    "- 全局表示以 `@` 开头，局部变量以 `%` 开头\n",
    "- 使用 `define` 关键字定义函数，在本例中定义了两个函数：`@test` 和 `@main`\n",
    "- `alloca` 指令用于在堆栈上分配内存，类似于 C 语言中的变量声明\n",
    "- `store` 指令用于将值存储到指定地址\n",
    "- `load` 指令用于加载指定地址的值\n",
    "- `add` 指令用于对两个操作数进行加法运算\n",
    "- `i32` 32 位 4 个字节的意思\n",
    "- `align` 字节对齐\n",
    "- `ret` 指令用于从函数返回"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "tags": [
     "hide-cell"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "; ModuleID = '.temp/test.c'\n",
      "source_filename = \".temp/test.c\"\n",
      "target datalayout = \"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128\"\n",
      "target triple = \"x86_64-pc-linux-gnu\"\n",
      "\n",
      "; Function Attrs: noinline nounwind optnone uwtable\n",
      "define dso_local void @test(i32 noundef %0, i32 noundef %1) #0 {\n",
      "  %3 = alloca i32, align 4\n",
      "  %4 = alloca i32, align 4\n",
      "  %5 = alloca i32, align 4\n",
      "  store i32 %0, ptr %3, align 4\n",
      "  store i32 %1, ptr %4, align 4\n",
      "  %6 = load i32, ptr %3, align 4\n",
      "  %7 = load i32, ptr %4, align 4\n",
      "  %8 = add nsw i32 %6, %7\n",
      "  store i32 %8, ptr %5, align 4\n",
      "  ret void\n",
      "}\n",
      "\n",
      "; Function Attrs: noinline nounwind optnone uwtable\n",
      "define dso_local i32 @main() #0 {\n",
      "  %1 = alloca i32, align 4\n",
      "  %2 = alloca i32, align 4\n",
      "  %3 = alloca i32, align 4\n",
      "  store i32 0, ptr %1, align 4\n",
      "  store i32 10, ptr %2, align 4\n",
      "  store i32 20, ptr %3, align 4\n",
      "  %4 = load i32, ptr %2, align 4\n",
      "  %5 = load i32, ptr %3, align 4\n",
      "  call void @test(i32 noundef %4, i32 noundef %5)\n",
      "  ret i32 0\n",
      "}\n",
      "\n",
      "attributes #0 = { noinline nounwind optnone uwtable \"frame-pointer\"=\"all\" \"min-legal-vector-width\"=\"0\" \"no-trapping-math\"=\"true\" \"stack-protector-buffer-size\"=\"8\" \"target-cpu\"=\"x86-64\" \"target-features\"=\"+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87\" \"tune-cpu\"=\"generic\" }\n",
      "\n",
      "!llvm.module.flags = !{!0, !1, !2, !3, !4}\n",
      "!llvm.ident = !{!5}\n",
      "\n",
      "!0 = !{i32 1, !\"wchar_size\", i32 4}\n",
      "!1 = !{i32 8, !\"PIC Level\", i32 2}\n",
      "!2 = !{i32 7, !\"PIE Level\", i32 2}\n",
      "!3 = !{i32 7, !\"uwtable\", i32 2}\n",
      "!4 = !{i32 7, !\"frame-pointer\", i32 2}\n",
      "!5 = !{!\"Ubuntu clang version 20.0.0 (++20240928031251+29d0a8470426-1~exp1~20240928151427.1956)\"}\n"
     ]
    }
   ],
   "source": [
    "!cat $temp_dir/test.ll"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py313",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
